﻿using System;
using System.ComponentModel;
using System.Globalization;
using System.Windows;
using System.Windows.Input;
using System.Windows.Media.Media3D;
using Wen.Core;

namespace Wen.UI.NavigationElements
{
	internal abstract class XyzControlViewModelBase : DependencyObject, INotifyPropertyChanged
	{
		#region Const

		internal static double DefaultStep = 0.1;
		private const int BigStepModifier = 5;

		#endregion

		#region Members

		private readonly ICommand _xPlusCommand;
		private readonly ICommand _xMinusCommand;
		private readonly ICommand _yPlusCommand;
		private readonly ICommand _yMinusCommand;
		private readonly ICommand _zPlusCommand;
		private readonly ICommand _zMinusCommand;
		private readonly ICommand _resetCommand;

		#endregion

		#region Properties

		public ICommand ZMinusCommand {
			get { return _zMinusCommand; }
		}

		public ICommand ZPlusCommand {
			get { return _zPlusCommand; }
		}

		public ICommand YMinusCommand {
			get { return _yMinusCommand; }
		}

		public ICommand YPlusCommand {
			get { return _yPlusCommand; }
		}

		public ICommand XMinusCommand {
			get { return _xMinusCommand; }
		}

		public ICommand XPlusCommand {
			get { return _xPlusCommand; }
		}

		public ICommand ResetCommand {
			get { return _resetCommand; }
		}

		protected virtual double Step { get { return DefaultStep; } }

		private double ActualStep {
			get { return Keyboard.Modifiers == ModifierKeys.Control ? Step * BigStepModifier : Step; }
		}

		#endregion

		#region Command impl

		private void ZMinusCommandImpl() {
			ApplyZMovement(-ActualStep);
			RaiseValueChanged();
		}

		private void ZplusCommandImpl() {
			ApplyZMovement(ActualStep);
			RaiseValueChanged();
		}

		private void YMinusCommandImpl() {
			ApplyYMovement(-ActualStep);
			RaiseValueChanged();
		}

		private void YPlusCommandImpl() {
			ApplyYMovement(ActualStep);
			RaiseValueChanged();
		}

		private void XMinusCommandImpl() {
			ApplyXMovement(-ActualStep);
			RaiseValueChanged();
		}

		private void XPlusCommandImpl() {
			ApplyXMovement(ActualStep);
			RaiseValueChanged();
		}

		private void ResetCommandImpl() {
			Reset();
			RaiseValueChanged();
		}

		#endregion

		#region Event

		internal EventHandler ValueChanged;
		private void RaiseValueChanged() {
			OnPropertyChanged("Coords");
			if (ValueChanged != null)
				ValueChanged.Invoke(this, new EventArgs());
		}

		#endregion

		internal XyzControlViewModelBase() {
			_xPlusCommand = new SimpleCommand(XPlusCommandImpl);
			_xMinusCommand = new SimpleCommand(XMinusCommandImpl);
			_yPlusCommand = new SimpleCommand(YPlusCommandImpl);
			_yMinusCommand = new SimpleCommand(YMinusCommandImpl);
			_zPlusCommand = new SimpleCommand(ZplusCommandImpl);
			_zMinusCommand = new SimpleCommand(ZMinusCommandImpl);
			_resetCommand = new SimpleCommand(ResetCommandImpl);
		}

		protected abstract void ApplyXMovement(double step);
		protected abstract void ApplyYMovement(double step);
		protected abstract void ApplyZMovement(double step);
		protected abstract void Reset();
		protected abstract Point3D RawCoords { get; }

		public string Coords {
			get { return string.Format(CultureInfo.InvariantCulture, "{0:0.##} {1:0.##} {2:0.##}", RawCoords.X, RawCoords.Y, RawCoords.Z); }
		}

		#region INotifyPropertyChanged

		public event PropertyChangedEventHandler PropertyChanged;

		protected void OnPropertyChanged(String info) {
			if (PropertyChanged != null) {
				PropertyChanged(this, new PropertyChangedEventArgs(info));
			}
		}

		#endregion
	}
}
